using BepuPhysics.CollisionDetection.CollisionTasks;
using BepuPhysics.Trees;
using BepuUtilities;
using BepuUtilities.Memory;
#if MYCODE
using BepuUtilities.Vectors;
#else
using System.Numerics;
#endif

namespace BepuPhysics.Collidables
{
    /// <summary>
    /// 定义可由Collidables用作形状的类型。
    /// </summary>
    public interface IShape
    {
        int TypeId { get; }
        ShapeBatch CreateShapeBatch(BufferPool pool, int initialCapacity, Shapes shapeBatches);
    }

    // 请注意,以下边界函数只需要一个方向,因为边界框上位置的效果对于所有形状都是相同的。
    // 通过将形状与位置分离,我们可以更容易地将位置表示换成更高精度的模式,而只修改实际
    // 直接与职位打交道。

    // 请注意,我们还支持一次性边界计算。有时甚至在发动机里也会用到它们。例如,将单个实体添加到仿真中。
    // 然而,请注意,我们不会费心在一次性变量上支持速度扩展。对于将对象添加到模拟的目的,这基本上是无关紧要的。
    // 我预计永远不会需要它,但是可以添加这样的实现……


    public interface IConvexShape : IShape
    {
        void ComputeBounds(in Quaternion orientation, out Vector3 min, out Vector3 max);
        void ComputeAngularExpansionData(out float maximumRadius, out float maximumAngularExpansion);

        void ComputeInertia(float mass, out BodyInertia inertia);

        bool RayTest(in RigidPose pose, in Vector3 origin, in Vector3 direction, out float t, out Vector3 normal);
    }

    /// <summary>
    /// 定义具有可能不同类型的子项的复合形状类型。
    /// </summary>
    public interface ICompoundShape : IShape, IBoundsQueryableCompound
    {
        // 请注意,复合形状没有宽的GetBound函数。由于化合物含有不同类型的形状,因此不能有效地将其矢量化。
        // 相反,它们的子级被添加到其他计算批中。
        void ComputeBounds(in Quaternion orientation, Shapes shapeBatches, out Vector3 min, out Vector3 max);
        void AddChildBoundsToBatcher(ref BoundingBoxBatcher batcher, in RigidPose pose, in BodyVelocity velocity, int bodyIndex);

        // 复合形状可能需要间接指向其他形状批次。这不是非常快,但无论如何,这个标量路径更多地是为了方便而不是性能而设计的。
        // 为了提高性能,应该使用批处理和矢量化的代码路径。
        void RayTest<TRayHitHandler>(in RigidPose pose, in RayData ray, ref float maximumT, Shapes shapeBatches, ref TRayHitHandler hitHandler) where TRayHitHandler : struct, IShapeRayHitHandler;
        void RayTest<TRayHitHandler>(in RigidPose pose, ref RaySource rays, Shapes shapeBatches, ref TRayHitHandler hitHandler) where TRayHitHandler : struct, IShapeRayHitHandler;
        int ChildCount { get; }
        ref CompoundChild GetChild(int compoundChildIndex);
        void Dispose(BufferPool pool);
    }

    /// <summary>
    /// 定义仅具有一种类型的子项的复合形状类型。
    /// </summary>
    /// <typeparam name="TChildShape">子形状的类型。</typeparam>
    /// <typeparam name="TChildShapeWide">子形状的类型,格式为AOSOA布局。</typeparam>
    public interface IHomogeneousCompoundShape<TChildShape, TChildShapeWide> : IShape, IBoundsQueryableCompound
        where TChildShape : IConvexShape
        where TChildShapeWide : IShapeWide<TChildShape>
    {
        void ComputeBounds(in Quaternion orientation, out Vector3 min, out Vector3 max);

        void RayTest<TRayHitHandler>(in RigidPose pose, in RayData ray, ref float maximumT, ref TRayHitHandler hitHandler) where TRayHitHandler : struct, IShapeRayHitHandler;
        void RayTest<TRayHitHandler>(in RigidPose pose, ref RaySource rays, ref TRayHitHandler hitHandler) where TRayHitHandler : struct, IShapeRayHitHandler;

        int ChildCount { get; }
        void GetLocalChild(int childIndex, out TChildShape childData);
        void GetPosedLocalChild(int childIndex, out TChildShape childData, out RigidPose childPose);
        void GetLocalChild(int childIndex, ref TChildShapeWide childData);
        void Dispose(BufferPool pool);
    }

    public interface IShapeWide<TShape> where TShape : IShape
    {

        /// <summary>
        /// 获取此类型是否支持按通道偏移量访问其内存。如果为false,则必须使用WriteSlot而不是WriteFirst。
        /// </summary>
        bool AllowOffsetMemoryAccess { get; }
        /// <summary>
        /// 获取宽形状内分配所需的字节数。
        /// </summary>
        int InternalAllocationSize { get; }
        /// <summary>
        /// 对于内部分配大小非零的类型,为用于内部分配的形状提供内存。
        /// 应该假定内存是堆栈分配的。
        /// </summary>
        /// <param name="memory">用于宽形状内部分配的内存。</param>
        void Initialize(in RawBuffer memory);

        /// <summary>
        /// 将指定的AOS格式的形状放入宽"this"引用的第一条车道中。
        /// </summary>
        /// <remarks>Note that we are effectively using the TShapeWide as a stride.
        /// 基址由此函数的用户偏移,因此实现只考虑第一个槽。</MARKETS>
        /// <param name="source">要从中收集的AOS格式的形状。</param>
        void WriteFirst(in TShape source);
        /// <summary>
        /// 将指定的AOS格式的形状放入宽"this"引用的选定槽中。
        /// </summary>
        /// <param name="index">要将数据放入的槽的索引。</param>
        /// <param name="source">要插入的数据源。</param>
        void WriteSlot(int index, in TShape source);
        void Broadcast(in TShape shape);

        void GetBounds(ref QuaternionWide orientations, int countInBundle, out Vector<float> maximumRadius, out Vector<float> maximumAngularExpansion, out Vector3Wide min, out Vector3Wide max);
        /// <summary>
        /// 获取要以宽方式执行的射线数的下限。光线较少的光线束将回退到单个光线代码路径。
        /// </summary>
        int MinimumWideRayCount { get; }
        void RayTest(ref RigidPoses poses, ref RayWide rayWide, out Vector<int> intersected, out Vector<float> t, out Vector3Wide normal);
    }

}
